﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration;
using System.Reflection;

using FMZJS.Model;

namespace FMZJS.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(string nameOrConnectionString)
            : base(nameOrConnectionString)
        {

        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>();
        }

        public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
        {
            return base.Set<TEntity>();
        }

        public void SetEntityState<TEntity>(TEntity entity, EntityState state) where TEntity : BaseEntity
        {
            this.Entry(entity).State = state;
        }

        /// <summary>
        /// 执行存储过程，返回实体集
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="commandText">存储过程名称</param>
        /// <param name="parameters">参数</param>
        /// <returns>返回实体集</returns>
        public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
        {
            bool hasOutputParameters = false;
            if (parameters != null)
            {
                foreach (var p in parameters)
                {
                    var outputP = p as DbParameter;
                    if (outputP == null)
                    {
                        continue;
                    }

                    if (outputP.Direction == ParameterDirection.InputOutput || outputP.Direction == ParameterDirection.Output)
                    {
                        hasOutputParameters = true;
                    }
                }
            }

            var context = ((IObjectContextAdapter)(this)).ObjectContext;

            //如果没有输出参数
            if (!hasOutputParameters)
            {
                var result = this.Database.SqlQuery<TEntity>(commandText, parameters).ToList();

                return result;
            }
            else
            {
                var connection = this.Database.Connection;
                if (connection.State == ConnectionState.Closed)
                {
                    connection.Open();
                }

                using (var cmd = connection.CreateCommand())
                {
                    cmd.CommandText = commandText;
                    cmd.CommandType = CommandType.StoredProcedure;

                    if (parameters != null)
                    {
                        foreach (var p in parameters)
                        {
                            cmd.Parameters.Add(p);
                        }
                    }

                    var reader = cmd.ExecuteReader();
                    var result = context.Translate<TEntity>(reader).ToList();
                    reader.Close();

                    return result;
                }
            }
        }

        /// <summary>
        /// 执行查询语句，返回一个实体集
        /// </summary>
        /// <typeparam name="TElement">实体类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns>Result</returns>
        public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
        {
            return this.Database.SqlQuery<TElement>(sql, parameters);
        }

        /// <summary>
        ///执行一个 DDL/DML 命令
        /// </summary>
        /// <param name="sql">命令语句</param>
        /// <param name="timeout">超时时间（单位秒），默认值为NULL</param>
        /// <param name="parameters">参数</param>
        /// <returns>返回影响行数</returns>
        public int ExecuteSqlCommand(string sql, int? timeout = null, params object[] parameters)
        {
            int? previousTimeout = null;
            if (timeout.HasValue)
            {
                previousTimeout = ((IObjectContextAdapter)this).ObjectContext.CommandTimeout;
                ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = timeout;
            }

            var result = this.Database.ExecuteSqlCommand(sql, parameters);

            if (timeout.HasValue)
            {
                ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = previousTimeout;
            }

            return result;
        }
    }
}
